<template>
  <div class="container">
    <el-card class="box-card">
      <template #header>
        <div class="card-header">
          <span>折角检测</span>
        </div>
      </template>
      
      <el-upload
        class="upload-demo"
        drag
        action="#"
        :auto-upload="false"
        :show-file-list="false"
        accept="image/*"
        @change="handleFileUpload"
      >
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          拖拽文件到此处或 <em>点击上传</em>
        </div>
      </el-upload>

      <div class="image-container" v-if="processedImage">
        <el-image 
          :src="processedImage" 
          fit="contain"
          :preview-src-list="[processedImage]"
        >
          <template #placeholder>
            <div class="image-placeholder">
              <el-icon><loading /></el-icon>
            </div>
          </template>
        </el-image>
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { UploadFilled, Loading } from '@element-plus/icons-vue'

const processedImage = ref<string>('')

const handleFileUpload = async (event: any) => {
  const file = event.raw
  if (!file) return

  const reader = new FileReader()
  reader.onload = (e) => {
    const img = new Image()
    img.onload = () => {
      // 创建canvas来处理图片
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      if (!ctx) return

      // 限制最大尺寸为1000px
      const maxSize = 1000
      let width = img.width
      let height = img.height
      
      if (width > maxSize || height > maxSize) {
        const ratio = Math.min(maxSize / width, maxSize / height)
        width *= ratio
        height *= ratio
      }

      canvas.width = width
      canvas.height = height
      ctx.drawImage(img, 0, 0, width, height)

      // 获取图像数据
      const imageData = ctx.getImageData(0, 0, width, height)
      const data = imageData.data

      // 转换为灰度图并增强对比度
      for (let i = 0; i < data.length; i += 4) {
        const avg = (data[i] + data[i + 1] + data[i + 2]) / 3
        // 增强对比度
        const enhanced = Math.min(255, Math.max(0, (avg - 128) * 1.5 + 128))
        data[i] = data[i + 1] = data[i + 2] = enhanced
      }

      // 应用自适应阈值
      const threshold = calculateAdaptiveThreshold(data, width, height)
      for (let i = 0; i < data.length; i += 4) {
        const value = data[i] > threshold ? 255 : 0
        data[i] = data[i + 1] = data[i + 2] = value
      }

      // 将处理后的图像数据放回canvas
      ctx.putImageData(imageData, 0, 0)

      // 检测边缘
      const edgeData = detectEdges(ctx, width, height)
      
      // 在原图上绘制检测到的折角
      ctx.drawImage(img, 0, 0, width, height)
      const corners = findCorners(edgeData, width, height)
      drawCorners(ctx, corners)

      processedImage.value = canvas.toDataURL()
    }
    img.src = e.target?.result as string
  }
  reader.readAsDataURL(file)
}

// 计算自适应阈值
const calculateAdaptiveThreshold = (data: Uint8ClampedArray, width: number, height: number) => {
  let sum = 0
  let count = 0
  
  for (let i = 0; i < data.length; i += 4) {
    sum += data[i]
    count++
  }
  
  return sum / count
}

// 边缘检测函数
const detectEdges = (ctx: CanvasRenderingContext2D, width: number, height: number) => {
  const imageData = ctx.getImageData(0, 0, width, height)
  const data = imageData.data
  const edgeData = new Uint8ClampedArray(width * height)

  // 使用改进的Sobel算子
  const sobelX = [-1, 0, 1, -2, 0, 2, -1, 0, 1]
  const sobelY = [-1, -2, -1, 0, 0, 0, 1, 2, 1]

  for (let y = 1; y < height - 1; y++) {
    for (let x = 1; x < width - 1; x++) {
      let gx = 0
      let gy = 0

      for (let ky = -1; ky <= 1; ky++) {
        for (let kx = -1; kx <= 1; kx++) {
          const idx = ((y + ky) * width + (x + kx)) * 4
          const gray = data[idx]
          const kernelIdx = (ky + 1) * 3 + (kx + 1)
          gx += gray * sobelX[kernelIdx]
          gy += gray * sobelY[kernelIdx]
        }
      }

      const magnitude = Math.sqrt(gx * gx + gy * gy)
      edgeData[y * width + x] = magnitude > 30 ? 255 : 0
    }
  }

  return edgeData
}

// 查找折角
const findCorners = (edgeData: Uint8ClampedArray, width: number, height: number) => {
  const corners: {x: number, y: number, score: number}[] = []
  const windowSize = 15
  const threshold = 0.6

  for (let y = windowSize; y < height - windowSize; y += 5) {
    for (let x = windowSize; x < width - windowSize; x += 5) {
      if (edgeData[y * width + x] > 0) {
        const score = calculateCornerScore(edgeData, x, y, width, height, windowSize)
        if (score > threshold) {
          corners.push({x, y, score})
        }
      }
    }
  }

  // 合并相近的角点
  return mergeCorners(corners, 20)
}

// 计算角点得分
const calculateCornerScore = (
  edgeData: Uint8ClampedArray, 
  x: number, 
  y: number, 
  width: number, 
  height: number,
  windowSize: number
) => {
  let edgeCount = 0
  let totalPoints = 0
  let directionChanges = 0
  let lastDirection = -1

  for (let dy = -windowSize; dy <= windowSize; dy++) {
    for (let dx = -windowSize; dx <= windowSize; dx++) {
      const nx = x + dx
      const ny = y + dy
      if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
        totalPoints++
        if (edgeData[ny * width + nx] > 0) {
          edgeCount++
          // 计算边缘方向
          const direction = Math.atan2(dy, dx)
          if (lastDirection !== -1) {
            const angleDiff = Math.abs(direction - lastDirection)
            if (angleDiff > Math.PI / 2) {
              directionChanges++
            }
          }
          lastDirection = direction
        }
      }
    }
  }

  const density = edgeCount / totalPoints
  const directionScore = directionChanges / edgeCount
  return density * directionScore
}

// 合并相近的角点
const mergeCorners = (corners: {x: number, y: number, score: number}[], distance: number) => {
  const merged: {x: number, y: number, score: number}[] = []
  
  for (const corner of corners) {
    let found = false
    for (const mergedCorner of merged) {
      const dx = corner.x - mergedCorner.x
      const dy = corner.y - mergedCorner.y
      const dist = Math.sqrt(dx * dx + dy * dy)
      
      if (dist < distance) {
        found = true
        if (corner.score > mergedCorner.score) {
          mergedCorner.x = corner.x
          mergedCorner.y = corner.y
          mergedCorner.score = corner.score
        }
        break
      }
    }
    
    if (!found) {
      merged.push({...corner})
    }
  }
  
  return merged
}

// 绘制检测到的折角
const drawCorners = (ctx: CanvasRenderingContext2D, corners: {x: number, y: number, score: number}[]) => {
  ctx.strokeStyle = 'red'
  ctx.lineWidth = 2

  for (const corner of corners) {
    ctx.beginPath()
    ctx.arc(corner.x, corner.y, 8, 0, Math.PI * 2)
    ctx.stroke()
  }
}
</script>

<style lang="scss" scoped>
.container {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
  
  .box-card {
    .card-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
  }

  .upload-demo {
    width: 100%;
    margin-bottom: 20px;
  }

  .image-container {
    margin-top: 20px;
    text-align: center;
    
    .el-image {
      max-width: 100%;
      max-height: 600px;
    }
  }

  .image-placeholder {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 200px;
    background: #f5f7fa;
    color: #909399;
    font-size: 30px;
  }
}
</style> 